package com.kate.mall.order.service.impl;

import cn.hutool.core.map.MapUtil;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.kate.mall.common.constants.OrderStatus;
import com.kate.mall.common.utils.IpUtil;
import com.kate.mall.common.utils.JacksonUtil;
import com.kate.mall.common.utils.ListMap2ListVoUtils2;
import com.kate.mall.common.utils.R;
import com.kate.mall.order.dto.*;
import com.kate.mall.order.entity.OrderEntity;
import com.kate.mall.order.feign.MemberFeignClient;
import com.kate.mall.order.feign.PromotionFeignClient;
import com.kate.mall.order.service.OrderService;
import com.kate.mall.order.service.WxOrderService;
import com.kate.mall.order.state.OrderStateManager;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.kate.mall.common.constants.WxResponseCode.*;

/**
 * @author 新梦想.陈超
 * @version 2021.2
 * @Description: {TODO}
 * @date 2023/6/29 下午2:57
 */
@Service
@Slf4j
@AllArgsConstructor
public class WxOrderServiceImpl implements WxOrderService {
    private OrderService orderService;
    private MemberFeignClient memberFeignClient;
    private ListMap2ListVoUtils2 listMap2ListVoUtils;
    private WxPayService wxPayService;
    private OrderStateManager orderStateManager;
    private PromotionFeignClient promotionFeignClient;
//    private NotifyService notifyService;


    @Transactional
    public R prepay(Integer userId, String body, HttpServletRequest request) {
        if (userId == null) {
            return R.unlogin();
        }
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        if (orderId == null) {
            return R.badArgument();
        }

        OrderEntity order = orderService.getById(orderId);
        if (order == null) {
            return R.badArgumentValue();
        }
        if (!order.getUserId().equals(userId)) {
            return R.badArgumentValue();
        }

        // 检测是否能够取消
        final Integer orderStatus = order.getOrderStatus();
        if (!order.getOrderStatus().equals(OrderStatus.WAIT_FOR_PAY)) {
            return R.error(ORDER_INVALID_OPERATION.getCode(), "订单不能支付");
        }
        R memberR = memberFeignClient.findMemberById(userId);
        final Map memberMap = MapUtil.get(memberR, "member", Map.class);
        final MemberDTO memberDTO = listMap2ListVoUtils.map2Vo(memberMap, null, MemberDTO.class);
        String openid = memberDTO.getWeixinOpenid();
        if (openid == null) {
            return R.error(AUTH_OPENID_UNACCESS.getCode(), "订单不能支付");
        }
        WxPayMpOrderResult result = null;
        try {
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            orderRequest.setOutTradeNo(order.getOrderSn());
            orderRequest.setOpenid(openid);
            orderRequest.setBody("订单：" + order.getOrderSn());
            // 元转成分
            int fee = 0;
            BigDecimal actualPrice = order.getActualPrice();
            fee = actualPrice.multiply(new BigDecimal(100)).intValue();
            orderRequest.setTotalFee(fee);
            orderRequest.setSpbillCreateIp(IpUtil.getIpAddr(request));

            result = wxPayService.createOrder(orderRequest);

            //缓存prepayID用于后续模版通知
            String prepayId = result.getPackageValue();
            prepayId = prepayId.replace("prepay_id=", "");
            WxUserFormidDTO userFormid = new WxUserFormidDTO();
            userFormid.setOpenid(memberDTO.getWeixinOpenid());
            userFormid.setFormid(prepayId);
            userFormid.setIsprepay(true);
            userFormid.setUseamount(3);
            userFormid.setExpireTime(LocalDateTime.now().plusDays(7));

            final R opResult = memberFeignClient.saveWxUserFormId(userFormid);
            if (!MapUtil.get(opResult, "errno", Integer.class).equals(0)) {
                throw new RuntimeException("添加预付记录失败.....");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.error(ORDER_PAY_FAIL.getCode(), "订单不能支付");
        }

        if (orderService.updateWithOptimisticLocker(order) == 0) {
            return R.updatedDateExpired();
        }
        return R.ok().put("data", result);

    }
    /** 
     * @author 新梦想.陈超
     * @date   2023/9/4 9:35 下午
     * @param  [request, response]
     * @return java.lang.Object
     * @Version1.0
     **/
    @Transactional
    public Object payNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String xmlResult = null;
        try {
            xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        } catch (IOException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        WxPayOrderNotifyResult result = null;
        try {
            result = wxPayService.parseOrderNotifyResult(xmlResult);

            if (!WxPayConstants.ResultCode.SUCCESS.equals(result.getResultCode())) {
                log.error(xmlResult);
                throw new WxPayException("微信通知支付失败！");
            }
            if (!WxPayConstants.ResultCode.SUCCESS.equals(result.getReturnCode())) {
                log.error(xmlResult);
                throw new WxPayException("微信通知支付失败！");
            }
        } catch (WxPayException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getMessage());
        }

        log.info("处理腾讯支付平台的订单支付");
        log.info("处理腾讯支付平台的订单支付结果为：{}", result);

        String orderSn = result.getOutTradeNo();
        String payId = result.getTransactionId();

        // 分转化成元
        String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());

        OrderEntity order = orderService.findBySn(orderSn);
        if (order == null) {
            return WxPayNotifyResponse.fail("订单不存在 sn=" + orderSn);
        }

        // 检查这个订单是否已经处理过
        if (order.getOrderStatus().equals(OrderStatus.FINISHED_PAY)) {
            return WxPayNotifyResponse.success("订单已经处理成功!");
        }

        // 检查支付订单金额
        if (!totalFee.equals(order.getActualPrice().toString())) {
            return WxPayNotifyResponse.fail(order.getOrderSn() + " : 支付金额不符合 totalFee=" + totalFee);
        }

        order.setPayId(payId);
        order.setPayTime(LocalDateTime.now());


        //设置订单状态
        OrderDTO orderDTO = order.clone(OrderDTO.class);
        orderStateManager.pay(orderDTO);
        order.setOrderStatus(orderDTO.getOrderStatus());

        if (orderService.updateWithOptimisticLocker(order) == 0) {
            // 这里可能存在这样一个问题，用户支付和系统自动取消订单发生在同时
            // 如果数据库首先因为系统自动取消订单而更新了订单状态；
            // 此时用户支付完成回调这里也要更新数据库，而由于乐观锁机制这里的更新会失败
            // 因此，这里会重新读取数据库检查状态是否是订单自动取消，如果是则更新成支付状态。
            order = orderService.findBySn(orderSn);
            int updated = 0;
            if (order.getOrderStatus().equals(OrderStatus.AUTO_CANCEL)) {
                order.setPayId(payId);
                order.setPayTime(LocalDateTime.now());
                order.setOrderStatus(OrderStatus.WAIT_FOR_DELIVERY);
                updated = orderService.updateWithOptimisticLocker(order);
            }

            // 如果updated是0，那么数据库更新失败
            if (updated == 0) {
                return WxPayNotifyResponse.fail("更新数据已失效");
            }
        }

        //  支付成功，有团购信息，更新团购信息
//        LitemallGroupon groupon = grouponService.queryByOrderId(order.getId());
        Map<String, Object> param = new HashMap<>();
        param.put("orderId", order.getId());
        final R grouponR = promotionFeignClient.queryGrouponByOrderId(param);
        final List<Map> grouponMapList = MapUtil.get((Map) grouponR.get("page"), "list", List.class);

        if (grouponMapList != null && grouponMapList.size() > 0) {
            final GrouponDTO grouponDTO = listMap2ListVoUtils.map2Vo(grouponMapList.get(0), null, GrouponDTO.class);

            final R grouponRulesR = promotionFeignClient.queryById(grouponDTO.getRulesId());
            final Map grouponRulesMap = MapUtil.get(grouponRulesR, "grouponRules", Map.class);
            final GrouponRulesDTO grouponRulesDTO = listMap2ListVoUtils.map2Vo(grouponRulesMap, null, GrouponRulesDTO.class);
            //仅当发起者才创建分享图片
//            if (grouponDTO.getGrouponId() == 0) {
//                String url = qCodeService.createGrouponShareImage(grouponRulesDTO.getGoodsName(), grouponRulesDTO.getPicUrl(), grouponDTO);
//                grouponDTO.setShareUrl(url);
//            }
            grouponDTO.setPayed(true);
            R updateGrouponR = promotionFeignClient.updateGroupon(grouponDTO);
            final Integer updateResult = MapUtil.get(updateGrouponR, "errno", Integer.class);
            if (MapUtil.get(updateGrouponR, "errno", Integer.class).equals(0)) {
                return WxPayNotifyResponse.fail("更新数据已失效");
            }

            // 团购已达成，更新关联订单支付状态
//            if (grouponDTO.getGrouponId() > 0) {
//                List<LitemallGroupon> grouponList = grouponService.queryJoinRecord(groupon.getGrouponId());
//                if (grouponList.size() >= grouponRules.getDiscountMember() - 1) {
//                    for (LitemallGroupon grouponActivity : grouponList) {
//                        if (grouponActivity.getOrderId().equals(order.getId())) {
//                            //当前订单
//                            continue;
//                        }
//
//                        LitemallOrder grouponOrder = orderService.findById(grouponActivity.getOrderId());
//                        if (grouponOrder.getOrderStatus().equals(OrderUtil.STATUS_PAY_GROUPON)) {
//                            grouponOrder.setOrderStatus(OrderUtil.STATUS_PAY);
//                            orderService.updateWithOptimisticLocker(grouponOrder);
//                        }
//                    }
//
//                    LitemallGroupon grouponSource = grouponService.queryById(groupon.getGrouponId());
//                    LitemallOrder grouponOrder = orderService.findById(grouponSource.getOrderId());
//                    if (grouponOrder.getOrderStatus().equals(OrderUtil.STATUS_PAY_GROUPON)) {
//                        grouponOrder.setOrderStatus(OrderUtil.STATUS_PAY);
//                        orderService.updateWithOptimisticLocker(grouponOrder);
//                    }
//                }
//
//            } else {
//                order = orderService.findBySn(orderSn);
//                order.setOrderStatus(OrderUtil.STATUS_PAY_GROUPON);
//                orderService.updateWithOptimisticLocker(order);
//            }
        }

            //TODO 发送邮件和短信通知，这里采用异步发送
            // 订单支付成功以后，会发送短信给用户，以及发送邮件给管理员
//        notifyService.notifyMail("新订单通知", order.toString());
            // 这里微信的短信平台对参数长度有限制，所以将订单号只截取后6位
//        notifyService.notifySmsTemplateSync(order.getMobile(), NotifyType.PAY_SUCCEED, new String[]{orderSn.substring(8, 14)});

            // 请依据自己的模版消息配置更改参数
//        String[] parms = new String[]{
//                order.getOrderSn(),
//                order.getOrderPrice().toString(),
//                DateTimeUtil.getDateTimeDisplayString(order.getAddTime()),
//                order.getConsignee(),
//                order.getMobile(),
//                order.getAddress()
//        };
//
//        notifyService.notifyWxTemplate(result.getOpenid(), NotifyType.PAY_SUCCEED, parms, "pages/index/index?orderId=" + order.getId());

            return WxPayNotifyResponse.success("处理成功!");
        }

}
